package code.example.base.cpu.iostate.state;

import code.example.tool.FixedThreadPool;
import code.example.tool.LogFactory;

import java.io.FileOutputStream;
import java.io.OutputStream;

/**
 * 启动脚本：java -cp lib/*:*.jar  code.example.base.cpu.iostate.state.TestIOState
 * 测试环境1：
 *      环境： 100条线程 ，不断的写文件（每次写入一字节并flush），主机8核cpu，
 *      现象：   iostat :%util 15%-20% 之间,写入一个字节时间（最长的） 100ms以上，
 *           线程状态：java.io.FileOutputStream.write(Native Method): java.lang.Thread.State: RUNNABLE
 *           vmstat: system cs（上下文切换） 指标在 1900左右。
 *                   r队列:100左右。
 *                   cpu us :8%左右。
 *                   cpu sy: 90%左右。
 *                   cpu wa: 0。
 *      表明： 磁盘io等待为0 ，可接受范围 ，
 *         cpu 的sy90% ，cpu太高了，大部时间都被系统占用了，用于上线文切换（cs指标）：
 *
 *          java 中write 方法调用后，磁盘写入时，由cpu与磁盘速度差异，cpu把写入任务交给DMA总线，
 *                               把写入线程状态表现为Runnable（操作系统中线程状态  为D(TASK_UNTNTERRUPTIBLE) ）但不可获得cpu时间片，把cpu时间片分给别的线程，
 *                               磁盘写入完成后，设置中断唤醒线程，再继续执行。
 *          每次写入一个字节，线程状态不断的切换（Running -->Runnable ....）,导于系统内核线程上下文切换使用大量时间。
 *
 *
 *
 *
 */
public class TestIOState {
    public void testState(String fileName){
        try {

            while(true){
                OutputStream os = new FileOutputStream(fileName);
                for(int i=0;i<10000;i++){
                    long startTime = System.currentTimeMillis();
                    os.write(i);
                    os.flush();
                    long useTime = System.currentTimeMillis() - startTime;
                    if(useTime >100){
                        LogFactory.getLog().info("write byte use time:"+useTime);
                    }


                }
                os.close();
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void test(){
        FixedThreadPool fixedThreadPool = new FixedThreadPool(100);
        for(int i=0;i<100;i++){
            final int id = i;
            fixedThreadPool.execute(new Runnable() {
                @Override
                public void run() {
                    testState("iostate"+id+".context");
                }
            });

        }
    }
    public static void main(String args []){
        TestIOState testIOState = new TestIOState();
        testIOState.test();
    }
}
